/*
 *  +----------------------------------------------------------------------
 *  | sophon [ A FAST GAME FRAMEWORK ]
 *  +----------------------------------------------------------------------
 *  | Copyright (c) 2023-2029 All rights reserved.
 *  +----------------------------------------------------------------------
 *  | Licensed ( http:www.apache.org/licenses/LICENSE-2.0 )
 *  +----------------------------------------------------------------------
 *  | Author: jqiris <1920624985@qq.com>
 *  +----------------------------------------------------------------------
 */

use std::process;
use std::sync::mpsc::{channel, Receiver, Sender};
use std::thread;

use super::*;

pub struct Writer {
    sender: Sender<LogItem>,
}

impl Writer {
    pub fn new() -> Self {
        let (tx, rx) = channel();
        Self::writing(rx);
        Self { sender: tx }
    }

    pub fn writing(rx: Receiver<LogItem>) {
        thread::spawn(move || loop {
            while let Ok(item) = rx.recv() {
                let logger = Logger::global_mut();
                logger.out_check();
                if item.allow_level < item.log_level {
                    continue;
                }
                let txt = item.log_format();
                if logger.out_type == OutType::OutStd || logger.out_type == OutType::OutAll {
                    logger.out_std(item.log_level.clone(), txt.clone());
                }
                if logger.out_type == OutType::OutFile || logger.out_type == OutType::OutAll {
                    if let Err(err) = logger.out_file(item.log_level.clone(), txt) {
                        eprintln!("{}", err);
                    }
                }
                if item.log_level == LogLevel::FATAL {
                    process::exit(1);
                }
            }
        });
    }
    pub fn send(&self, msg: LogItem) {
        self.sender.send(msg).unwrap();
    }
}

unsafe impl Sync for Writer {}

unsafe impl Send for Writer {}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_writer() {
        let w = Writer::new();
        let item = LogItem {
            log_txt: "test".to_string(),
            ..Default::default()
        };
        w.send(item);
    }
}
